import { useLocation, useParams } from "react-router-dom";
import Container from 'react-bootstrap/Container';
import Form from 'react-bootstrap/Form';
import { API_URI } from '../constants/index';


import Header from '../components/Header';
import Block from '../components/Block';
import { SourcesList, Source } from '../components/SourcesList';
import { TopicsList, Topic } from '../components/TopicsList';
import { Button, ProgressBar } from "react-bootstrap";
import { useState, useEffect } from "react";
import { streamingApiCall } from '../helpers/streaming';
import { apiCall } from '../helpers/api';
// import { getContact } from "../contacts";

export async function loader({ params }: any) {
    // const token = await getContact(params.token);
    const token = params.token;
    return { token };
}

type Params = {
    token: string;
}

interface StateData {
    idea: string,
    sources: Array<Source>,
    topics: Array<Topic>,
    review: string,
};

interface IntermediateData<T> {
    sources: Array<T>,
};

interface IntermediateDataTopic {
    topics: Array<Topic>,
};

interface IntermediateDataReview {
    text: string,
};

interface State {
    data: string;
    id: string;
    parent_state?: string;
    timestamp: string;
};

interface Chunk {
    done: boolean,
    current_step?: number,
    total_steps?: number,
    data: State | IntermediateData<Source> | IntermediateDataTopic | IntermediateDataReview,
};

export default function Project() {
    const { token } = useParams<Params>();
    const [stateId, setStateId] = useState<string | null>(null);
    const [stateIdHistory, setStateIdHistory] = useState<Array<string>>([]);

    const [idea, setIdea] = useState('');
    const ideaChange = (event: {target: {value: string}}) => {
        setIdea(event.target.value);
    };

    const [sourcesProgress, setSourcesProgress] = useState<number>(0.0);
    const [itemsLoaded, setItemsLoaded] = useState<boolean>(false);
    const [sourcesItems, setSourcesItems] = useState<Array<Source>>([]);
    const [needAppend, setNeedAppend] = useState<boolean>(true);

    const [topicsProgress, setTopicsProgress] = useState<number>(0.0);
    const [topicsLoaded, setTopicsLoaded] = useState<boolean>(false);
    const [topicsItems, setTopicsItems] = useState<Array<Topic>>([]);
    const [needAppendTopics, setNeedAppendTopics] = useState<boolean>(true);

    const [reviewProgress, setReviewProgress] = useState<number>(0.0);
    const [reviewLoaded, setReviewLoaded] = useState<boolean>(false);
    const [reviewContent, setReviewContent] = useState<string>('');
    const reviewContentChange = (event: {target: {value: string}}) => {
        setReviewContent(event.target.value);
    };

    const applyState = (state: State) => {
        const state_data = JSON.parse(state.data) as StateData;

        setStateId(state.id);
        setStateIdHistory(stateIdHistory.concat([state.id]));

        setIdea(state_data.idea);
        setSourcesItems(state_data.sources);
        setTopicsItems(state_data.topics);
        setReviewContent(state_data.review);
        setItemsLoaded(true);
        setTopicsLoaded(true);
        setReviewLoaded(true);
    }

    const reload = (newStateId?: string) => {
        apiCall(
            '/reload' + (
                newStateId ? ('?state_id=' + newStateId) : ''
            ),
            token!,
            {},
        ).then((result: State) => {
            applyState(result);
        });
    };

    const goBack = () => {
        console.log('goBack', stateIdHistory.length);
        console.log('history', stateIdHistory)
        if (stateIdHistory.length <= 1) {
            return;
        }
        const prevState = stateIdHistory[stateIdHistory.length - 2];
        setStateIdHistory(stateIdHistory.slice(0, stateIdHistory.length - 1));
        reload(prevState);
    };

    const location = useLocation();
    useEffect(() => {
        reload();
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [location.key]);

    const sourcesStart = async () => {
        console.log('Start sources search...');
        setSourcesProgress(0);
        let items: Array<Source> = [];
        if (needAppend) {
            sourcesItems.forEach((item, i) => {items.push(item)});
        }
        setItemsLoaded(false);
        const result = await streamingApiCall(
            '/action/sources/start',
            token!,
            {
                idea: idea,
                append: needAppend,
                state_id: stateId,
            },
            (chunk: Chunk) => {
                console.log('new chunk:', chunk);
                if (!chunk.done) {
                    const chunk_items = chunk.data as IntermediateData<Source>;
                    items = items.concat(chunk_items.sources);
                    setSourcesItems(items);
                    setSourcesProgress(Math.round(100 * chunk.current_step! / chunk.total_steps!));
                }
            }
        );
        console.log('Final result:', result);
        const final_result = result as Chunk;
        const final_state = final_result.data as State;
        applyState(final_state);
        setSourcesProgress(100);
    };

    const updateSourcesItems = async (newItems: Array<Source>) => {
        await apiCall(
            '/action/sources/update',
            token!,
            {
                sources: newItems,
                state_id: stateId,
            },
        );
        setSourcesItems(newItems);
    };

    const deleteSource = async (index: number) => {
        console.log('Delete source:', index);
        let newItems: Array<Source> = sourcesItems.map((item, i) => {
            if (i === index) {
                item.disabled = true;
            }
            return item;
        });
        await updateSourcesItems(newItems);
    };

    const restoreSource = async (index: number) => {
        console.log('Restore source:', index);
        let newItems: Array<Source> = sourcesItems.map((item, i) => {
            if (i === index) {
                item.disabled = false;
            }
            return item;
        });
        await updateSourcesItems(newItems);
    };

    // topics

    const topicsStart = async () => {
        console.log('Start topics search...');
        setTopicsProgress(0);
        let items: Array<Topic> = [];
        if (needAppendTopics) {
            topicsItems.forEach((item, i) => {items.push(item)});
        }
        setTopicsLoaded(false);
        const result = await streamingApiCall(
            '/action/topics/start',
            token!,
            {
                idea: idea,
                append: needAppendTopics,
                state_id: stateId,
            },
            (chunk: Chunk) => {
                console.log('new chunk:', chunk);
                if (!chunk.done) {
                    const chunk_items = chunk.data as IntermediateDataTopic;
                    items = items.concat(chunk_items.topics);
                    setTopicsItems(items);
                    setTopicsProgress(Math.round(100 * chunk.current_step! / chunk.total_steps!));
                }
            }
        );
        console.log('Final result (topics):', result);
        const final_result = result as Chunk;
        const final_state = final_result.data as State;
        applyState(final_state);
        setTopicsProgress(100);
    };

    const updateTopicsItems = async (newItems: Array<Topic>) => {
        await apiCall(
            '/action/topics/update',
            token!,
            {
                topics: newItems,
                state_id: stateId,
            },
        );
        setTopicsItems(newItems);
    };

    const deleteTopic = async (index: number) => {
        console.log('Delete topic:', index);
        let newItems: Array<Topic> = topicsItems.map((item, i) => {
            if (i === index) {
                item.disabled = true;
            }
            return item;
        });
        await updateTopicsItems(newItems);
    };

    const restoreTopic = async (index: number) => {
        console.log('Restore topic:', index);
        let newItems: Array<Topic> = topicsItems.map((item, i) => {
            if (i === index) {
                item.disabled = false;
            }
            return item;
        });
        await updateTopicsItems(newItems);
    };

    // review

    const reviewStart = async () => {
        console.log('Start review...');
        setReviewProgress(0);
        let reviewText = "";
        setReviewLoaded(false);
        const result = await streamingApiCall(
            '/action/review/start',
            token!,
            {
                idea: idea,
                sources: sourcesItems,
                topics: topicsItems,
                review: reviewContent,
                state_id: stateId,
            },
            (chunk: Chunk) => {
                console.log('new chunk:', chunk);
                if (!chunk.done) {
                    const chunk_items = chunk.data as IntermediateDataReview;
                    reviewText = reviewText + chunk_items.text;
                    setReviewContent(reviewText);
                    setReviewProgress(Math.round(100 * chunk.current_step! / chunk.total_steps!));
                }
            }
        );
        console.log('Final result (topics):', result);
        const final_result = result as Chunk;
        const final_state = final_result.data as State;
        applyState(final_state);
        setReviewProgress(100);
    };

    const updateReview = async () => {
        await apiCall(
            '/action/review/update',
            token!,
            {
                review: reviewContent,
                state_id: stateId,
            },
        );
    };

    const exportLatex = () => {
        window.open(API_URI + '/export/latex/' + token + '/' + stateId, "_blank");
    };


    // const { token } = useLoaderData();
    return (
        <Container className="p-3">
            <Header exportLatex={exportLatex} goBack={goBack} />
            <Container className="p-5 mb-4 bg-light rounded-3">
                {/*<h1 className="header">
              Статья для токена {token}
            </h1>*/}
                <Block header="Описание" isText={false}>
                    <Form>
                        <Form.Group className="mb-3" controlId="exampleForm.ControlTextarea1">
                            <Form.Label>Краткое описание Вашей статьи или её идеи:</Form.Label>
                            <Form.Control as="textarea" value={idea} onChange={ideaChange} rows={3} />
                        </Form.Group>
                    </Form>
                </Block>
                <Block header="Источники" isText={false}>
                    {
                        !itemsLoaded ? (
                            <ProgressBar now={sourcesProgress} label={`${sourcesProgress}%`} visuallyHidden />
                        ) : ''
                    }
                    <Button variant="primary" className="pull-right mt-1 mb-1" active onClick={sourcesStart}>
                        Подобрать источники
                    </Button>
                    <Form>
                        <Form.Check // prettier-ignore
                            type="switch"
                            label="Дополнить список"
                            checked={needAppend}
                            onChange={()=>{setNeedAppend(!needAppend)}}
                        />
                    </Form>
                    <SourcesList
                        items={sourcesItems}
                        deleteSource={deleteSource}
                        restoreSource={restoreSource}
                        itemsLoaded={itemsLoaded}
                    />
                </Block>
                {/* <Block header="Аннотация">...</Block> */}
                <Block header="Темы для обзора литературы" isText={false}>
                    {
                        !topicsLoaded ? (
                            <ProgressBar now={topicsProgress} label={`${topicsProgress}%`} visuallyHidden />
                        ) : ''
                    }
                    <Button variant="primary" className="pull-right mt-1 mb-1" active onClick={topicsStart}>
                        Сформулировать список тем
                    </Button>
                    <Form>
                        <Form.Check // prettier-ignore
                            type="switch"
                            label="Дополнить список"
                            checked={needAppendTopics}
                            onChange={()=>{setNeedAppendTopics(!needAppendTopics)}}
                        />
                    </Form>
                    <TopicsList
                        items={topicsItems}
                        deleteTopic={deleteTopic}
                        restoreTopic={restoreTopic}
                        itemsLoaded={topicsLoaded}
                    />
                </Block>
                <Block header="Обзор литературы" isText={false}>
                    {
                        !reviewLoaded ? (
                            <ProgressBar now={reviewProgress} label={`${reviewProgress}%`} visuallyHidden />
                        ) : ''
                    }
                    <Button variant="primary" className="pull-right mt-1 mb-1" active onClick={reviewStart}>
                        Сгенерировать обзор
                    </Button>
                    <Form.Control as="textarea" value={reviewContent} onChange={reviewContentChange} rows={10} />
                    <Button variant="primary" className="pull-right mt-3 mb-1 mr-2" active onClick={updateReview}>
                        Сохранить
                    </Button>{' '}
                    <Button variant="primary" className="pull-right mt-3 ml-2 mb-1" active onClick={exportLatex}>
                        Экспорт latex
                    </Button>
                </Block>
                {/*
                <Block header="Название">
                    <Form.Control size="lg" type="text" placeholder="Название статьи" />
                    <br />
                    Другие варианты от GigaChat:
                    <ListGroup className="mt-1">
                        <ListGroup.Item action href="#link1">
                            Название статьи
                        </ListGroup.Item>

                        <ListGroup.Item action href="#link2">
                            Link 2
                        </ListGroup.Item>
                        <ListGroup.Item action>
                            This one is a button
                        </ListGroup.Item>
                    </ListGroup>
                </Block>
                */}
            </Container>
        </Container>
    );
}